// webSocket.ts
import { WSS_SERVER_URL } from "@/config/socket";
type WebSocketUrl = string;

interface WebSocketMessage {
  state: number;
  method: string;
}

interface SendMessageOptions {
  data: string;
}

interface CloseSocketOptions {
  reason?: string;
  success?: () => void;
  fail?: (err: any) => void;
}

class webSocketClass {
  private url: WebSocketUrl | string;
  private data: WebSocketMessage | null = null;
  private isCreate: boolean = false; // WebSocket 是否创建成功
  private isConnect: boolean = false; // 是否已经连接
  private isInitiative: boolean = false; // 是否主动断开
  private timeoutNumber: number; // 心跳检测间隔（秒）
  private heartbeatTimer: ReturnType<typeof setInterval> | null = null; // 心跳检测定时器
  private reconnectTimer: ReturnType<typeof setTimeout> | null = null; // 断线重连定时器
  private socketExamples: UniNamespace.SocketTask | null = null; // websocket实例
  private againTime: number; // 重连等待时间(单位秒)&&金价刷新时间
  private timeOut: boolean = false; // 是否连接超时

  constructor(url: string = WSS_SERVER_URL, time: number = 60) {
    this.url = url;

    this.timeoutNumber = time;
    this.againTime = 1;
    this.initSocket();
  }

  // 初始化websocket连接
  public initSocket(): void {
    try {
      this.socketExamples = uni.connectSocket({
        url: this.url,
        success: () => {
          this.isCreate = true;
        },
        fail: () => {
          this.isCreate = false;
        },
      });
      this.createSocket();
    } catch (error) {}
  }

  // 创建websocket连接
  private createSocket(): void {
    if (this.isCreate && this.socketExamples) {
      // 监听 WebSocket 连接打开事件
      try {
        this.socketExamples.onOpen(() => {
          this.isConnect = true;
          if (this.heartbeatTimer) clearInterval(this.heartbeatTimer);
          if (this.reconnectTimer) clearTimeout(this.reconnectTimer);

          // 打开心跳检测
          this.heartbeatCheck();
        });

        // 监听 WebSocket 接受到服务器的消息事件
        this.socketExamples.onMessage((res) => {
          const data = JSON.parse(res.data);
          uni.$emit("marketUpdate", data);
        });

        // 监听 WebSocket 连接关闭事件
        this.socketExamples.onClose(() => {
          this.isConnect = false;
          this.reconnect();
        });

        // 监听 WebSocket 错误事件
        this.socketExamples.onError((res) => {
          this.timeOut =
            res.errMsg.includes("Timed") || res.errMsg.includes("Invalid HTTP");
        });
      } catch (error) {
        console.warn(error);
      }
    } else {
      console.warn("WebSocket 初始化失败!");
    }
  }

  // 发送消息
  public sendMsg(value: WebSocketMessage): Promise<boolean> {
    const param = JSON.stringify(value);
    return new Promise((resolve, reject) => {
      if (!this.socketExamples) {
        reject(new Error("WebSocket 实例未初始化"));
        return;
      }

      this.socketExamples.send({
        data: param,
        success() {
          resolve(true);
        },
        fail(error) {
          reject(error);
        },
      });
    });
  }

  // 开启心跳检测
  private heartbeatCheck(): void {
    this.data = {
      state: 1,
      method: "heartbeat",
    };

    this.heartbeatTimer = setInterval(() => {
      if (this.data) {
        this.sendMsg(this.data);
      }
    }, this.timeoutNumber * 1000);
  }

  // 重新连接
  private reconnect(): void {
    // 停止发送心跳
    if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
    if (this.heartbeatTimer) clearInterval(this.heartbeatTimer);

    // 如果不是人为关闭的话，进行重连
    if (!this.isInitiative) {
      this.reconnectTimer = setTimeout(() => {
        this.initSocket();
      }, this.againTime * 1000);
    }
  }

  public setIsInitiativeFalse(): void {
    this.isInitiative = false;
  }

  public setIsInitiativeTrue(): void {
    this.isInitiative = true;
  }

  // 关闭 WebSocket 连接
  public closeSocket(reason: string = "关闭"): void {
    if (this.socketExamples) {
      this.socketExamples.close({
        reason,
        success: () => {
          this.data = null;
          this.isCreate = false;
          this.isConnect = false;
          this.isInitiative = true;
          this.socketExamples = null;
          if (this.heartbeatTimer) clearInterval(this.heartbeatTimer);
          if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
        },
        fail: (err) => {},
      });
    }
  }
}

export default webSocketClass;
